package com.codeoss.framework.view.renderer;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.metadata.TableData;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.util.ValueNamePair;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.component.chart.ChartDataItemDef;
import com.codeoss.framework.view.component.chart.IndicatorTable;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.datasource.IDataSource;
import com.codeoss.framework.view.datasource.store.IDataSourceStore;

@Service("indicatortableRenderer")
public class IndicatorTableRenderer extends AbstractChartRenderer {
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private IDataSourceStore dataSourceStore;
	protected void startRenderView(YunContext yunContext, Component component, ViewSerializeMap viewSerializeMap) {
		super.startRenderView(yunContext, component, viewSerializeMap);
		IndicatorTable indicatorTable=(IndicatorTable)component;
		viewSerializeMap.put("title", indicatorTable.getTitle());
		viewSerializeMap.put("subtitle", indicatorTable.getSubtitle());
		viewSerializeMap.put("col", indicatorTable.getCol());
		viewSerializeMap.put("bigScreen", indicatorTable.isBigScreen());
		if(indicatorTable.getDimensionList().size()==0) {
			viewSerializeMap.put("subType","kpi");
		}else if(indicatorTable.getDimensionList().size()==1) {
			viewSerializeMap.put("subType","indicatortable");
		}
	}
	
	protected PropSerializeMap startRenderProp(YunContext yunContext,
			Component component, ViewPropMap viewPropMap) {
		PropSerializeMap propSerializeMap=super.startRenderProp(yunContext, component, viewPropMap);
		IndicatorTable indicatorTable=(IndicatorTable)component;
		if(indicatorTable.getDimensionList().size()==0) {
			BigDecimal value=yunContext.getAttribute(component.getId()+"_chartdata");
			propSerializeMap.put("value", value);
		}else if(indicatorTable.getDimensionList().size()==1) {
			Map<String,Object> resultMap=getIndicatorTableRenderValue(yunContext, component);
			propSerializeMap.put("data", resultMap);
		}
		return propSerializeMap;
	}
	
	protected Map<String,Object> getIndicatorTableRenderValue(YunContext yunContext,Component component){
		IndicatorTable indicatorTable=(IndicatorTable)component;
		Page page = yunContext.getPage();
		DataSourceConfig dataSourceConfig = page.getDataSourceConfigById(indicatorTable.getDataSource());
		Table table=tableStore.get(dataSourceConfig.getTableName());
		List<Map<String, Object>> mapList = yunContext.getAttribute(component.getId()+"_chartdata");
		if(mapList==null||mapList.size()==0) {
			return null;
		}
		Map<String, BigDecimal> dataMap = new HashMap<String, BigDecimal>();
		List<List<Object>> dimensionValueListList = new ArrayList<List<Object>>();
		Map<String,Long> lengthMap=new HashMap<String,Long>();
		List<Column> columnList=new ArrayList<Column>();
		List<ChartDataItemDef> dimensionList = indicatorTable.getDimensionList();
		List<ChartDataItemDef> measureList = indicatorTable.getMeasureList();
		for (int i = 0; i < dimensionList.size(); i++) {
			dimensionValueListList.add(new ArrayList<Object>());
			Column column=table.getColumnByColumnName(dimensionList.get(i).getField());
			columnList.add(column);
		}
		
		for (int i = 0; i < mapList.size(); i++) {
			Map<String, Object> map = mapList.get(i);
			String dimensionKey=getTwoDimensionKey(yunContext, indicatorTable, map, dimensionValueListList);
			BigDecimal fieldValue = dataMap.get(dimensionKey);
			for (int k = 0; k < measureList.size(); k++) {
				String measureField = measureList.get(k).getField();
				Object measureValue = map.get(measureField);
				String aggregateType = measureList.get(k).getAggregateType();
				if ("sum".equals(aggregateType)) {
					if(fieldValue==null) {
						fieldValue=new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					dataMap.put(dimensionKey, fieldValue);
				}else if("average".equals(aggregateType)) {
					if(fieldValue==null) {
						fieldValue=new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					dataMap.put(dimensionKey, fieldValue);
					Long length=lengthMap.get(dimensionKey);
					if(length==null) {
						length=1L;
					}else {
						length++;
					}
					lengthMap.put(dimensionKey, length);
				}else if("count".equals(aggregateType)) {
					if(fieldValue==null) {
						fieldValue=new BigDecimal(0);
					}
					fieldValue=fieldValue.add(new BigDecimal(1));
					dataMap.put(dimensionKey, fieldValue);
				}else if("min".equals(aggregateType)) {
					if(fieldValue==null) {
						dataMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					}else if(new BigDecimal(measureValue + "").compareTo(fieldValue)<0) {
						fieldValue=new BigDecimal(measureValue + "");
						dataMap.put(dimensionKey, fieldValue);
					}
				}else if("max".equals(aggregateType)) {
					if(fieldValue==null) {
						dataMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					}else if(new BigDecimal(measureValue + "").compareTo(fieldValue)>0) {
						fieldValue=new BigDecimal(measureValue + "");
						dataMap.put(dimensionKey, fieldValue);
					}
				}
			}
		}
		boolean isAverageAggregateType="average".equals(measureList.get(0).getAggregateType());
		if(isAverageAggregateType) {
			Iterator<Map.Entry<String,BigDecimal>> it=dataMap.entrySet().iterator();
			while(it.hasNext()) {
				Map.Entry<String,BigDecimal> entry=it.next();
				long length=lengthMap.get(entry.getKey());
				if(length>0) {
					dataMap.put(entry.getKey(), entry.getValue().divide(new BigDecimal(length)));
				}
			}
		}
		List<Map<String,String>> fieldValueMapList=new ArrayList<Map<String,String>>();
		for(int i=0;i<columnList.size();i++) {
			Column column=columnList.get(i);
			Map<String,String> fieldValueMap=new HashMap<String,String>();
			fieldValueMapList.add(fieldValueMap);
			List<Object> dimensionValueList=dimensionValueListList.get(i);
			if(column.getLookupInfo()!=null&&column.getLookupInfo().getDataSourceConfig()!=null) {
				Table fieldTable=tableStore.get(column.getLookupInfo().getDataSourceConfig().getTableName());
				IDataSource dataSource=dataSourceStore.getDataSource(fieldTable.getAccessType());
				Query query=new Query();
				query.add(Restrictions.in(fieldTable.getPrimaryKeyColumn().getColumnName(), dimensionValueList));
				TableData tableData=dataSource.select(yunContext, fieldTable, query);
				List<Map<String,Object>> data=tableData.getData();
				for(int j=0;j<data.size();j++) {
					Map<String,Object> dataItem=data.get(j);
					fieldValueMap.put(dataItem.get(column.getLookupInfo().getValueColumn())+"",(String)dataItem.get(column.getLookupInfo().getDisplayColumn()));
				}
			}else {
				for(int j=0;j<dimensionValueList.size();j++) {
					fieldValueMap.put(dimensionValueList.get(j)+"", dimensionValueList.get(j)+"");
				}
			}
		}
		List<Object> dimensionValueList=dimensionValueListList.get(0);
		
		Map<String,Object> resultMap=new HashMap<String,Object>();
		
		List<ValueNamePair> resultList=new ArrayList<ValueNamePair>();
		resultMap.put("list", resultList);
		for(int i=0;i<dimensionValueList.size();i++) {
			Object object=dimensionValueList.get(i);
			BigDecimal value=dataMap.get(object+"");
			String name=fieldValueMapList.get(0).get(object+"");
			ValueNamePair pair=new ValueNamePair(name,value);
			resultList.add(pair);
		}
		String dimensionOrderType=dimensionList.get(0).getOrderType();
		if(!StringUtils.isEmpty(dimensionOrderType)) {
			if("asc".equals(dimensionOrderType)) {
				resultList.sort(new Comparator<ValueNamePair>() {

					@Override
					public int compare(ValueNamePair o1, ValueNamePair o2) {
						// TODO Auto-generated method stub
						return o1.getName().compareTo(o2.getName());
					}
					
				});
			}else if("desc".equals(dimensionOrderType)) {
				resultList.sort(new Comparator<ValueNamePair>() {

					@Override
					public int compare(ValueNamePair o1, ValueNamePair o2) {
						// TODO Auto-generated method stub
						return o2.getName().compareTo(o1.getName());
					}
					
				});
			}
		}
		String measureOrderType=measureList.get(0).getOrderType();
		if(!StringUtils.isEmpty(measureOrderType)) {
			if("asc".equals(measureOrderType)) {
				resultList.sort(new Comparator<ValueNamePair>() {

					@Override
					public int compare(ValueNamePair o1, ValueNamePair o2) {
						// TODO Auto-generated method stub
						return ((BigDecimal)o1.getValue()).compareTo((BigDecimal)o2.getValue());
					}
					
				});
			}else if("desc".equals(measureOrderType)) {
				resultList.sort(new Comparator<ValueNamePair>() {

					@Override
					public int compare(ValueNamePair o1, ValueNamePair o2) {
						// TODO Auto-generated method stub
						return ((BigDecimal)o2.getValue()).compareTo((BigDecimal)o1.getValue());
					}
					
				});
			}
		}
		int topN=indicatorTable.getTopN();
		if(topN>0 && resultList.size()>topN) {
			int c=resultList.size()-topN;
			for(int i=0;i<c;i++) {
				resultList.remove(resultList.size()-1);
			}
		}
		String aggregateType = measureList.get(0).getAggregateType();
		ValueNamePair header=null;
		if("sum".equals(aggregateType)) {
			BigDecimal total=new BigDecimal(0);
			for(int i=0;i<dimensionValueList.size();i++) {
				Object object=dimensionValueList.get(i);
				BigDecimal value=dataMap.get(object+"");
				total=total.add(value);
			}
			header=new ValueNamePair("总共",total);
		}else if("average".equals(aggregateType)) {
			BigDecimal total=new BigDecimal(0);
			for(int i=0;i<dimensionValueList.size();i++) {
				Object object=dimensionValueList.get(i);
				BigDecimal value=dataMap.get(object+"");
				total=total.add(value);
			}
			BigDecimal averageValue=total.divide(new BigDecimal(dimensionValueList.size()));
			header=new ValueNamePair("平均",averageValue);
		}else if("min".equals(aggregateType)) {
			BigDecimal minValue=dataMap.get(dimensionValueList.get(0)+"");
			for(int i=1;i<dimensionValueList.size();i++) {
				BigDecimal value=dataMap.get(dimensionValueList.get(i)+"");
				if(minValue.compareTo(value)>0) {
					minValue=value;
				}
			}
			header=new ValueNamePair("最小值",minValue);
		}else if("max".equals(aggregateType)) {
			BigDecimal maxValue=dataMap.get(dimensionValueList.get(0)+"");
			for(int i=1;i<dimensionValueList.size();i++) {
				BigDecimal value=dataMap.get(dimensionValueList.get(i)+"");
				if(maxValue.compareTo(value)<0) {
					maxValue=value;
				}
			}
			header=new ValueNamePair("最大值",maxValue);
		}else if("count".equals(aggregateType)) {
			BigDecimal total=new BigDecimal(0);
			for(int i=0;i<dimensionValueList.size();i++) {
				Object object=dimensionValueList.get(i);
				BigDecimal value=dataMap.get(object+"");
				total=total.add(value);
			}
			BigDecimal averageValue=total.divide(new BigDecimal(dimensionValueList.size()));
			header=new ValueNamePair("数量",averageValue);
		}
		resultMap.put("header", header);
		return resultMap;
	}
}
